/**
 * @file game.cpp
 * @brief Game class methods implementation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3 of the License.
 *
 * @author VestniK (Sergey N.Vidyuk) sir.vestnik@gmail.com
 * @date 17 Oct 2008
 */
#include "game.h"

// Pseudo random generator functions
#include <cstdlib>

#include <QtCore/QDateTime>

#include "serverplayer.h"

using namespace mjn;

Game::Game() {
   mWind = East;
   mState = Game::WaitingForPlayers;
   mTileSet.fillSet();
   mDiscardedTile = NULL_TILE_ID;
}

/**
 * Creates new player and connects it to this game. If 4 players already
 * connected no new player created. Created player is owned by the Game
 * instance.
 *
 * @returns pointer to the newly created player or 0 if game is full.
 */
ServerPlayer *Game::addNewPlayer() {
    if ( mPlayers.count() < PLAYERS_COUNT ) {
        ServerPlayer *p = new ServerPlayer(this);
        mPlayers.append(p);
        if (mPlayers.count() == PLAYERS_COUNT) mState = Game::ReadyToStart;
        return p;
    }
    return 0;
}

/**
 * Returns true if all 4 players are connected to game otherwise returns false.
 */
bool Game::noSlots() const {
   if ( mPlayers.count() < PLAYERS_COUNT ) {
      return false;
   }
   return true;
}

/**
 * Tries to start the game. If there are 4 players connected to this game it
 * will be started otherwise not.
 *
 * @return true if game is started or false if not enough players connected to
 * this game.
 */
bool Game::start() {
    if ( mPlayers.count() != PLAYERS_COUNT ) {
        return false;
    }
    mState = Game::Started;
    srand( QDateTime::currentDateTime().toTime_t() );
    int EastWindPlayerIndx = rand() % mPlayers.size();
    int indx = 0;
    foreach ( ServerPlayer *player, mPlayers ) {
        switch ( (EastWindPlayerIndx + indx)%PLAYERS_COUNT ) {
            case 0: player->setPlayerWind(East); break;
            case 1: player->setPlayerWind(South); break;
            case 2: player->setPlayerWind(West); break;
            case 3: player->setPlayerWind(North); break;
        }
        indx++;
    }
    // Starting first (east wind) set
    startSet(East);
    return true;
}

void Game::startSet( WindType wind ) {
   mWind = wind;
   startRound();
}

void Game::startRound() {
   mWall.buildWall(mTileSet);
   currentPlayer = East;
   ServerPlayer *current = 0;
   foreach ( ServerPlayer* p, mPlayers ) {
      p->beginRound();
      if ( p->playerWind() == currentPlayer ) {
         current = p;
      }
   }
   mDiscardedTile = -1;
   current->makeTurn(true);
}

void Game::nextTurn(TileID discardedTile) {
   mDiscardedTile = discardedTile;
   emit tileDiscarded(mDiscardedTile);
   // if round failed
   if ( mWall.isOver() ) {
      emit roundFailed();
      this->startRound(); // restarting current round
      return;
   }
   // Switch current player and run next turn
   switch( currentPlayer ) {
      case East: currentPlayer = South; break;
      case South: currentPlayer = West; break;
      case West: currentPlayer = North; break;
      case North: currentPlayer = East; break;
      default: currentPlayer = East; break;
   }
   foreach ( ServerPlayer* p, mPlayers ) {
      if ( p->playerWind() == currentPlayer ) {
         p->makeTurn();
         break;
      }
   }
}

TileID Game::takeDiscardedTile() {
   TileID res = mDiscardedTile;
   mDiscardedTile = NULL_TILE_ID;
   return res;
}
